package top.whysu.gps.utils;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Pattern;

/**
 * 日期工具类, 继承org.apache.commons.lang.time.DateUtils类
 */
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(DateUtils.class);

    public static String[] parsePatterns = {"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss",
            "yyyy.MM.dd HH:mm", "yyyy.MM", "yyyy-MM-dd HH", "yyyyMMddHHmmss"};

    private static Pattern p = Pattern.compile("[yMdHms]");

    /**
     * 得到当前日期字符串 格式（yyyy-MM-dd）
     */
    public static String getDate() {
        return getDate("yyyy-MM-dd");
    }

    /**
     * 得到当前日期字符串 格式（yyyy-MM-dd） pattern可以为："yyyy-MM-dd" "HH:mm:ss" "E"
     */
    public static String getDate(String pattern) {
        return DateFormatUtils.format(new Date(), pattern);
    }

    /**
     * 得到日期字符串 默认格式（yyyy-MM-dd） pattern可以为："yyyy-MM-dd" "HH:mm:ss" "E"
     */
    public static String formatDate(Date date, Object... pattern) {
        String formatDate = null;
        if (pattern != null && pattern.length > 0) {
            formatDate = DateFormatUtils.format(date, pattern[0].toString());
        } else {
            formatDate = DateFormatUtils.format(date, "yyyy-MM-dd");
        }
        return formatDate;
    }

    /**
     * 得到日期时间字符串，转换格式（yyyy-MM-dd HH:mm:ss）
     */
    public static String formatDateTime(Date date) {
        return formatDate(date, "yyyy-MM-dd HH:mm:ss");
    }

    /**
     * 得到当前时间字符串 格式（HH:mm:ss）
     */
    public static String getTime() {
        return formatDate(new Date(), "HH:mm:ss");
    }

    /**
     * 得到当前日期和时间字符串 格式（yyyy-MM-dd HH:mm:ss）
     */
    public static String getDateTime() {
        return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
    }

    /**
     * 得到当前年份字符串 格式（yyyy）
     */
    public static String getYear() {
        return formatDate(new Date(), "yyyy");
    }

    /**
     * 得到当前月份字符串 格式（MM）
     */
    public static String getMonth() {
        return formatDate(new Date(), "MM");
    }

    /**
     * 得到月份字符串 格式（MM）
     *
     * @return
     */
    public static String getMonth(Date date) {
        return formatDate(date, "MM");
    }

    /**
     * 得到当天字符串 格式（dd）
     */
    public static String getDay() {
        return formatDate(new Date(), "dd");
    }

    /**
     * 得到当前星期字符串 格式（E）星期几
     */
    public static String getWeek() {
        return formatDate(new Date(), "E");
    }

    /**
     * 日期型字符串转化为日期 格式 { "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm",
     * "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy.MM.dd",
     * "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm" ,"yyyy-MM-dd HH"} 至少包含年月日，否则无法转换
     */
    public static Date parseDate(Object str) {
        if (str == null) {
            return null;
        }
        try {
            return parseDate(str.toString(), parsePatterns);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 获取过去的天数
     *
     * @param date
     * @return
     */
    public static long pastDays(Date date) {
        long t = System.currentTimeMillis() - date.getTime();
        return t / (24 * 60 * 60 * 1000);
    }

    /**
     * 获取过去的小时
     *
     * @param date
     * @return
     */
    public static long pastHour(Date date) {
        long t = System.currentTimeMillis() - date.getTime();
        return t / (60 * 60 * 1000);
    }

    /**
     * 获取过去的分钟
     *
     * @param date
     * @return
     */
    public static long pastMinutes(Date date) {
        long t = System.currentTimeMillis() - date.getTime();
        return t / (60 * 1000);
    }

    /**
     * 转换为时间（天,时:分:秒.毫秒）
     *
     * @param timeMillis
     * @return
     */
    public static String formatDateTime(long timeMillis) {
        long day = timeMillis / (24 * 60 * 60 * 1000);
        long hour = (timeMillis / (60 * 60 * 1000) - day * 24);
        long min = ((timeMillis / (60 * 1000)) - day * 24 * 60 - hour * 60);
        long s = (timeMillis / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
        long sss = (timeMillis - day * 24 * 60 * 60 * 1000 - hour * 60 * 60 * 1000 - min * 60 * 1000 - s * 1000);
        return (day > 0 ? day + "," : "") + hour + ":" + min + ":" + s + "." + sss;
    }

    /**
     * 转换为时间（*天*小时*分*秒）,调用时最好加上try catch
     *
     * @param ss 精确到秒
     * @return *天*小时*分*秒
     */
    public static String longToDateTime(long ss) {
        String dateTimes;
        long days = ss / (60 * 60 * 24);
        long hours = (ss % (60 * 60 * 24)) / (60 * 60);
        long minutes = (ss % (60 * 60)) / 60;
        long seconds = ss % 60;
        if (days > 0) {
            if (seconds > 0) {
                dateTimes = days + "天" + hours + "小时" + minutes + "分" + seconds + "秒";
            } else {
                if (minutes > 0) {
                    dateTimes = days + "天" + hours + "小时" + minutes + "分";
                } else {
                    if (hours > 0) {
                        dateTimes = days + "天" + hours + "小时";
                    } else {
                        dateTimes = days + "天";
                    }
                }
            }
        } else if (hours > 0) {
            if (seconds > 0) {
                dateTimes = hours + "小时" + minutes + "分" + seconds + "秒";
            } else {
                if (minutes > 0) {
                    dateTimes = hours + "小时" + minutes + "分";
                } else {
                    dateTimes = hours + "小时";
                }
            }
        } else if (minutes > 0) {
            if (seconds > 0) {
                dateTimes = minutes + "分" + seconds + "秒";
            } else {
                dateTimes = minutes + "分";
            }
        } else {
            dateTimes = seconds + "秒";
        }
        return dateTimes;
    }

    /**
     * 获取两个日期之间的天数
     *
     * @param before
     * @param after
     * @return
     */
    public static double getDistanceOfTwoDate(Date before, Date after) {
        long beforeTime = before.getTime();
        long afterTime = after.getTime();
        return (afterTime - beforeTime) / (1000 * 60 * 60 * 24);
    }

    /**
     * 获取当月的 天数
     */
    public static int getCurrentMonthDay() {
        Calendar a = Calendar.getInstance();
        a.set(Calendar.DATE, 1);
        a.roll(Calendar.DATE, -1);
        return a.get(Calendar.DATE);
    }

    /**
     * 根据年 月 获取对应的月份 天数
     */
    public static int getDaysByYearMonth(int year, int month) {
        Calendar a = Calendar.getInstance();
        a.set(Calendar.YEAR, year);
        a.set(Calendar.MONTH, month - 1);
        a.set(Calendar.DATE, 1);
        a.roll(Calendar.DATE, -1);
        return a.get(Calendar.DATE);
    }

    /**
     * 根据日期 找到对应日期的 星期
     */
    public static String getDayOfWeekByDate(String date) {
        String dayOfweek = "-1";
        try {
            SimpleDateFormat myFormatter = new SimpleDateFormat("yyyy-MM-dd");
            Date myDate = myFormatter.parse(date);
            SimpleDateFormat formatter = new SimpleDateFormat("E");
            dayOfweek = formatter.format(myDate);
        } catch (Exception ignored) {

        }
        return dayOfweek;
    }

    /**
     * 根据年、月获取当月第一天
     *
     * @param year
     * @param month
     * @return
     */
    public static String getFirstDayByYearMonth(int year, int month) {
        Calendar a = Calendar.getInstance();
        a.set(Calendar.YEAR, year);
        a.set(Calendar.MONTH, month - 1);
        a.set(Calendar.DAY_OF_MONTH, 1);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

        return format.format(a.getTime());
    }

    /**
     * 根据年、月获取当月最后一天
     *
     * @param year
     * @param month
     * @return
     */
    public static String getLastDayByYearMonth(int year, int month) {
        Calendar a = Calendar.getInstance();
        a.set(Calendar.YEAR, year);
        a.set(Calendar.MONTH, month);
        a.set(Calendar.DAY_OF_MONTH, 0);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

        return format.format(a.getTime());
    }

    /**
     * 获取当前日期的前几天
     *
     * @param date
     * @param interval
     * @return
     */
    public static Date getDaysAgo(Date date, int interval) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, -interval);
        return calendar.getTime();
    }

    public static Date getMonthsAgo(Date date, int interval) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, -interval);
        return calendar.getTime();
    }

    /**
     * 获取到指定月份的第一天
     *
     * @param date
     * @return
     */
    public static Date getFirstDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, 0);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTime();
    }

    /**
     * 当前时间加减n秒
     *
     * @param second
     * @param plus:true为加，false为减
     * @return
     */
    public static String timeAddOrDiv(int second, boolean plus) {
        if (!plus) {
            second = (-second);
        }
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, second);
        // 这个是你要转成后的时间的格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        // 时间戳转换成时间
        String sd1 = sdf.format(new Date(Long.parseLong(String.valueOf(calendar.getTimeInMillis()))));
        return sd1;
    }

    /**
     * 计算两个字符串的时间差
     * <p>
     * 返回时间差毫秒数
     *
     * @param t1
     * @param t2
     * @return
     */
    public static long diffTwoTime(String t1, String t2) {
        long diff = 0;
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date one;
        Date two;
        try {
            one = df.parse(t1);
            two = df.parse(t2);
            long time1 = one.getTime();
            long time2 = two.getTime();
            if (time1 < time2) {
                diff = time2 - time1;
            } else {
                diff = time1 - time2;
            }
        } catch (ParseException e) {
            LOGGER.error("计算两个字符串的时间差异常，入参t1: {}, t2: {}", new Object[]{t1, t2, e});
        }
        return diff;
    }

    /**
     * 时间字节数组转换为字符串   格式 2016-03-02 16:55:00(兼容小端)
     *
     * @param time 字节数组
     * @return 时间字符串
     */
    public static String byteArrayToTime(byte[] time) {
        int second = 0;
        if (time.length == 7) {
            byte[] dateTime = getDateTimeByteArray();
            // 兼容安凯小端时间模式
            if (time[6] == dateTime[0] && time[5] == dateTime[1] && time[4] == dateTime[2]) {
                return String.format("%02d%02d-%02d-%02d %02d:%02d:%02d", time[6], time[5], time[4], time[3], time[2],
                        time[1], time[0]);
            }
            second = time[6];
        }
        return String.format("%02d%02d-%02d-%02d %02d:%02d:%02d", time[0], time[1], time[2], time[3], time[4], time[5], second);
    }

    /**
     * 获取当前时间
     * 7个字节，十六进制表示，2015年9月18日17点18分21秒，则为14 0F 09 12 11 12 15
     *
     * @return 时间字节数组
     */
    public static byte[] getDateTimeByteArray() {
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String nowStr = sf.format(calendar.getTime());
        byte[] dateTime = new byte[7];
        dateTime[0] = Byte.valueOf(nowStr.substring(0, 2));
        dateTime[1] = Byte.valueOf(nowStr.substring(2, 4));
        dateTime[2] = Byte.valueOf(nowStr.substring(5, 7));
        dateTime[3] = Byte.valueOf(nowStr.substring(8, 10));
        dateTime[4] = Byte.valueOf(nowStr.substring(11, 13));
        dateTime[5] = Byte.valueOf(nowStr.substring(14, 16));
        dateTime[6] = Byte.valueOf(nowStr.substring(17, 19));
        return dateTime;
    }

    /**
     * 时间字符串 转换为6字节数组
     *
     * @param time 格式 2016-03-02 16:55
     * @return
     */
    public static byte[] timeToByteArray6(String time) {
        byte[] dateTime = new byte[6];
        if (time == null || time.length() < 16) {
            return dateTime;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        try {
            Date date = sdf.parse(time);
            // 变成标准格式字符串
            String dateStr = sdf.format(date);
            dateTime[0] = Byte.valueOf(dateStr.substring(0, 2));
            dateTime[1] = Byte.valueOf(dateStr.substring(2, 4));
            dateTime[2] = Byte.valueOf(dateStr.substring(5, 7));
            dateTime[3] = Byte.valueOf(dateStr.substring(8, 10));
            dateTime[4] = Byte.valueOf(dateStr.substring(11, 13));
            dateTime[5] = Byte.valueOf(dateStr.substring(14, 16));
        } catch (Exception e) {
            LOGGER.error("时间字符串 转换为6字节数组异常，入参：{}", new Object[]{time, e});
        }
        return dateTime;
    }

    /**
     * 时间戳转换为6字节数组
     *
     * @param time 格式 2016-03-02 16:55
     * @return
     */
    public static byte[] timeToByteArray6(Long time) {
        byte[] dateTime = new byte[6];
        if (time == null) {
            return dateTime;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        try {
            // 变成标准格式字符串
            String dateStr = sdf.format(new Date(time));
            dateTime[0] = Byte.valueOf(dateStr.substring(0, 2));
            dateTime[1] = Byte.valueOf(dateStr.substring(2, 4));
            dateTime[2] = Byte.valueOf(dateStr.substring(5, 7));
            dateTime[3] = Byte.valueOf(dateStr.substring(8, 10));
            dateTime[4] = Byte.valueOf(dateStr.substring(11, 13));
            dateTime[5] = Byte.valueOf(dateStr.substring(14, 16));
        } catch (Exception e) {
            LOGGER.error("时间戳转换为6字节数组异常，入参：{}", new Object[]{time, e});
        }
        return dateTime;
    }

    /**
     * 获取当前时间的Date对象（格式：yyyy-MM-dd HH:mm:ss）
     *
     * @return
     */
    public static Date getCurrentDate() {
        String dateTime = getDateTime();
        Date date = parseDate(dateTime);
        return date;
    }

    /**
     * 获取year年后的当前时间
     *
     * @param year
     * @return
     */
    public static Date getDateAfterYear(int year) {
        Date date = new Date();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.YEAR, year);
        String format = df.format(calendar.getTime());
        Date yearDate = parseDate(format);
        return yearDate;
    }

    /**
     * 将时间戳转换为时间
     *
     * @param s
     * @return
     */
    public static Date stampToDate(Long s) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date(s);
        String res = simpleDateFormat.format(date);
        Date resultDate = parseDate(res);
        return resultDate;
    }


    /**
     * 将字符串类型时间，结束时间推迟一天，转换成字符串
     *
     * @param endDateStr
     * @return
     */
    public static String getEndDate(String endDateStr) {
        // 将前端传过来的时间格式 yyyy-MM-dd  拼接成 yyyy-MM-dd HH:MM:ss 注意中间的空格
        endDateStr = endDateStr.trim() + " 00:00:00";
        Date date = DateUtils.parseDate(endDateStr);
        // 获取当前结束时间的后一天的0点 作为结束时间 如传进来8号0点为结束，就推迟为9号0点作为结束
        Date endDate = DateUtils.getDaysAgo(date, -1);
        // 返回，转成yyyy-MM-dd HH:MM:ss
        return formatDateTime(endDate);
    }


    /**
     * @description: 根据出生日期计算年龄
     * @author: guoyuxuan@2019/9/17 16:31
     * @param: [birthDay 字符串类型]
     * @return: int
     * @throws:
     */
    public static String getAge(String birthDay) throws Exception {
        birthDay = formatBirthday(birthDay);
        if (StringUtils.isBlank(birthDay)) {
            return birthDay;
        }
        Integer birthYear = Integer.valueOf(birthDay);
        Integer yearNow = Calendar.getInstance().get(Calendar.YEAR);
        if (birthYear > yearNow) { //出生日期晚于当前时间，无法计算
            LOGGER.error("出生日期晚于当前时间，无法计算！");
            return "";
        }

        Integer age = yearNow - birthYear;
        if (age == 0) {
            return "1";
        } else {
            return age + "";
        }
    }

    /**
     * 格式化出生日期
     *
     * @param birthDayStr
     * @return
     * @throws ParseException
     */
    private static String formatBirthday(String birthDayStr) throws ParseException {
        if (StringUtils.isEmpty(birthDayStr) || birthDayStr.length() < 4) {
            return "";
        }

        birthDayStr = birthDayStr.replaceAll("-", "").replaceAll("\\.", "").replaceAll("/", "").replaceAll(":", "")
                .replaceAll(" ", "");
        if (birthDayStr.length() < 4) {
            return "";
        }

        birthDayStr = birthDayStr.substring(0, 4);

        return birthDayStr;
    }

    /**
     * 当天凌晨0点0分0秒Date
     *
     * @return
     */
    public static Date getCurrentDayZero() {
        Calendar calendar1 = Calendar.getInstance();
        calendar1.set(calendar1.get(Calendar.YEAR), calendar1.get(Calendar.MONTH), calendar1.get(Calendar.DAY_OF_MONTH),
                0, 0, 0);
        return calendar1.getTime();
    }

    /**
     * 获取当天23点59分59秒Date
     *
     * @return
     */
    public static Date getCurrentDayLast() {
        Calendar calendar2 = Calendar.getInstance();
        calendar2.set(calendar2.get(Calendar.YEAR), calendar2.get(Calendar.MONTH), calendar2.get(Calendar.DAY_OF_MONTH),
                23, 59, 59);
        return calendar2.getTime();
    }

    /**
     * 获取两个日期之间的时间差(秒)
     */
    public static long getMillionsOfTwoDate(String beiginTime, String endTime) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        Date dateBegin = sdf.parse(beiginTime);
        Date dateEnd = sdf.parse(endTime);
        long between = dateEnd.getTime() - dateBegin.getTime();
        return between / 1000;
    }

}
